debug指令,參數r是Register暫存器
-r
AX=0000 BX=0000 CX=0000 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000
DS=08FA ES=08FA SS=08FA CS=08FA IP=0100 NV UP EI NG NZ NA PE NC
08FA:0100 C3 RET
可以一眼望去所有的暫存器及目前的值。
而d,是dump, 把記憶體內容秀出來
-d ds:0000
08FA:0000 CD 20 BF 9F 00 9A F0 FE-1D F0 9F 1D 62 03 C6 07 . ..........b...
08FA:0010 8B 02 47 02 9B 02 62 03-01 01 01 00 02 FF FF FF ..G...b.........
08FA:0020 FF FF FF FF FF FF FF FF-FF FF FF FF 48 03 54 59 ............H.TY
08FA:0030 62 03 14 00 18 00 FA 08-00 00 62 03 00 00 00 00 b.........b.....
08FA:0040 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
08FA:0050 CD 21 CB 00 00 00 00 00-00 00 00 00 00 20 20 20 .!...........
08FA:0060 20 20 20 20 20 20 20 20-00 00 00 00 00 20 20 20 .....
08FA:0070 20 20 20 20 20 20 20 20-00 00 00 00 00 00 00 00 ........
其實這兩個圖,十數年前就看過,每看必走馬看花,近中年後,才有耐性品味一下。
1。暫存器中,大多為0,唯獨一個SP不為0,顯然不是放值的單純用途。待會還會提到。
2。而dump的記憶段,08FA:0000 ,而目前,DS/ES/SS/CS都是08FA,表示在同一記憶體段,
那一個程式或是call別人的lib,或是程式很長,一個segment放不下去,這時會怎麼分配呢?
進入今天的練習
今天的練習來自加拿大女教授的教學片,The 80x86 Runtime Stackhttp://www.youtube.com/watch?v=enAZwo43o0Q&feature=plcp,
筆者看了幾次,修改了其中的些code, 讓堆疊的效果突顯出來,
大家都知道,堆疊是模擬生活中的疊書本,書一本一本的疊上去,
一般情況下,最上面的書是剛擺上去的,愈早放的書,放愈下面。PUSH就是把書放上去,
POP就把書拿出來。
練習的code如下:
C:\>debug
-a cs:100
08FA:0100 push ax
08FA:0101 push ax
08FA:0102 push ax
08FA:0103 push ax
08FA:0104 pop ax
08FA:0105 pop ax
08FA:0106 pop ax
-r ax
AX 0000 :aabb
此時暫存器內容是
AX=AABB,SP=FFFE ,SS=08FA , IP=0100
我們觀察幾個暫存器之間的變化。
t是一步一步的執行。
連續4次push ax,
我們看到,SP(推疊指標由FFFE變成FFFC變成FFFA變成FFF8變成FFF6)
而SS堆疊段記憶體(-d ss:fff0)的變化情況是
08FA:FFF0 00 00 00 01 00 00 01 01-FA 08 86 73 BB AA 00 00
08FA:FFF0 01 01 00 00 02 01 FA 08-86 73 BB AA BB AA 00 00
08FA:FFF0 00 00 03 01 FA 08 86 73-BB AA BB AA BB AA 00 00
08FA:FFF0 04 01 FA 08 86 73 BB AA-BB AA BB AA BB AA 00 00
再連續3次pop ax
SP(推疊指標由FFF6變成FFF8變成FFFA變成FFFC)
而SS堆疊段記憶體(-d ss:fff0)的變化情況是
08FA:FFF0 04 01 FA 08 86 73 BB AA-BB AA BB AA BB AA 00 00
08FA:FFF0 00 00 05 01 FA 08 86 73-BB AA BB AA BB AA 00 00
08FA:FFF0 FA 08 00 00 06 01 FA 08-86 73 BB AA BB AA 00 00
08FA:FFF0 00 00 FA 08 00 00 07 01-FA 08 86 73 BB AA 00 00
發揮一點想像力,把BB AA想像是一本書,記憶體的變化,就像放下四本書,再拿上三本書的情況。
此時IP指令指標,在一旁記錄著程式的運作,由101, 102, 103, 104, 105, 106,107的
動作。
這裏特別注意的是,SS堆疊段,佔用08FA段的尾部,而push動作,是往前寫入記憶,而pop是往後寫入記憶體。
比較:和影片中的segment比較,它是用0B3C的segment,而SP是指向FFEE,
但填入記憶體的方式是一致的。
補充:為什麼寫入暫存器是AABB,秀在記憶體是BBAA呢?
這是所謂的Little Endian,請參閱
http://www.prudentman.idv.tw/2007/11/big-endianlittle-endian.html
在朱邦復先生的組合語言之藝術,
http://cbflabs.com/book/asm/asm/10.htm
朱老先生的一段話,做為今天實驗的結束
舉例說,有個圖形值在AX中,要寫進 DI 所指記憶區位置中,寫完以後,AX要向右移一位再繼續寫,直到CX═0。
這是一個非常簡單,而且經常用到的動作,可是在使用「倒裝定址」時,麻煩就來了。
假設AX值為4567H ,DI指向記憶區2000H ,倒裝的放法,是先將AL的值放進2000H 的記憶單位中,再將AH放進2001H 的記憶單位裏。如果從由小到大的定址觀點來看,這就等於是在2000H 中放了一個十六位元的值6745H 。
這倒不打緊,因為再從記憶位址2000H 中放回 AX 時,仍然成為4567H 。問題是在作圖時,一旦4567H 變成了6745H ,圖形就左右顛倒了。補救的方法,是在放進記憶區之前,先將AH及AL交換,放完以後,再重新交換回來。說來不算大事,可是白白浪費了兩個指令的時間及空間。對速度極關緊要的畫圖顯示而言,要畫幾萬個點,所累積的時間就不可小觀了。
除此之外,在寫程式時,對圖形的效應要能掌握,才會有良好的成果,像這樣每次轉來轉去,頭都昏了,自然而然就失去了耐性。
現在,80386 CPU 問世了,且不談效果,讀者可以試想,把32位元的 12345678H轉換成 78563412H要多少道手續?
這種痛苦的手續,也是美國人不願意用組合語言的理由之一。在高階語言中,有編譯器代勞,問題好像不大。但對效率的要求而言,就得不償失了。圖形功能是當今及未來電腦的主流之一,由於當初設計者沒有遠見,導致無窮的後患。
問題尚不止於此,IBM PC/AT 的系統空間,在定址的理論上,可以有 1MB(暫時不必考慮記憶擴充及EMS 等問題),然而真正能提供作為程式執行的空間,卻不足 600KB。
高中時...我的同學每天在看這些code 改PC Game 三國志的數值...我沒學會...
退伍後...我的同事每天研究這些,在改...線上遊戲的數值...我也還是沒學會...
現在...
之後要參考另外一段在youtube放教學片,其作者,是一個小朋友,我很好奇,
小朋友,為什麼會特別去用dos,又去學組合語言,然後又搞懂後出影片。
昨天本想寫上朱邦復先生是我前進的力量,
分享給你 ,
朱老先生學電腦時,已近40歲,從basic學起,之後就切入組合語言,
倉頡輸入法讓他大名不朽,其實讓他從一而終反而是中文系統,
中文字型寫到cpu裏…
我也還在弄懂中,程式至少是11~15天之後才寫出來。
對你們第一線工程師,腦容量還有多少可以榨出來,身體(後背)還有多少空間可以拔罐,這更是業餘再業餘的興趣了
謝謝timloo大大鼓勵
換了一張圖
photo credit: <a href="http://www.flickr.com/photos/patrickgage/3738107746/">Patrick Gage</a> via <a href="http://photopin.com">photopin</a> <a href="http://creativecommons.org/licenses/by-nc-sa/2.0/">cc</a>
non commerical 可用於非營利用途,
還不錯用。
老外的資訊人,書本的量一樣驚人。